# -*- coding: utf-8 -*-
# created on 2016/6/2


from mathsolver.functions.base import *
from sympy import Poly, factor, solve_univariate_inequality, solveset
from sympy.abc import x
from mathsolver.functions.sympy_utils import get_all_child, default_symbol
from mathsolver.functions.fangcheng.base import ercifangcheng_judge
from mathsolver.functions.root.jiefangchen import JieFangChen


def judgement_parts(xx):
    if len(xx.free_symbols) > 0:
        if xx.is_Pow:
            if xx.args[1] < 0:
                return True
            elif xx.args[1] == 0:
                return True
            else:
                q = xx.args[1].q
                if (q % 2) == 0:
                    return True
    else:
        return False


def get_parts(expr):
    childrens = []
    # if judgement_parts(expr):
    #     return [expr]
    for arg in expr.args:
        if len(arg._args) == 2:
            if judgement_parts(arg):
                childrens.append(arg)
        elif len(arg._args) > 2:
            childrens.extend(get_parts(arg))
    return childrens


# 判断一元二次方程解的情况
class ErCi001(BaseFunction):
    @staticmethod
    def to_latex(token):
        if token.is_Number and token > 0:
            return new_latex(token)
        else:
            return "(%s)" % new_latex(token)

    def solver(self, *args):
        f1, f2 = args[0].sympify()
        target_symbol = default_symbol(f1 - f2)
        if ercifangcheng_judge(f1 - f2, target_symbol):
            symbols = (f1 - f2).free_symbols
            if len(symbols) == 1:
                symbol = symbols.pop()
                if not f2.is_zero:
                    f = Add(f1, -f2).expand()
                    self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
                else:
                    f = f1

                poly = Poly(f.as_expr(), symbol)
                a, b, c = poly.all_coeffs()
                if b < 0:
                    formula = "(%s)^2-4*%s*%s" % (new_latex(b), new_latex(a), new_latex(c))
                else:
                    formula = "%s^2-4*%s*%s" % (new_latex(b), new_latex(a), new_latex(c))

                value = b ** 2 - 4 * a * c
                self.steps.append(["因为", "\\bigtriangleup = b^2 - 4ac = %s = %s" % (formula, new_latex(value))])
                if value > 0:
                    self.steps.append(["所以方程有两个不相等的实数根", ""])
                elif value == 0:
                    self.steps.append(["所以方程有两个相等的实数根", ""])
                else:
                    self.steps.append(["所以方程没有实数根", ""])
                self.label.add("判断不含参的一元二次方程解的情况")

            elif len(symbols) == 2:
                target = symbols.difference([x]).pop()
                if not f2.is_zero:
                    f = Add(f1, -f2).expand()
                    self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
                else:
                    f = f1

                poly = Poly(f.as_expr(), x)
                a, b, c = poly.all_coeffs()
                latex_a = self.to_latex(a)
                latex_b = self.to_latex(b)
                latex_c = self.to_latex(c)

                formula = "%s^2-4*%s*%s" % (latex_b, latex_a, latex_c)
                value = factor(b ** 2 - 4 * a * c)
                self.steps.append(["", "\\bigtriangleup = b^2 - 4ac = %s = %s" % (formula, new_latex(value))])

                if value.is_zero:
                    self.steps.append(["因为\\bigtriangleup = 0", "所以方程有两个相等的实数根"])
                else:
                    answer1 = solve_univariate_inequality(Rel(value, S.Zero, "<="), target, relational=False)
                    answer2 = solve_univariate_inequality(Rel(value, S.Zero, ">="), target, relational=False)
                    answer3 = solve_univariate_inequality(Rel(value, S.Zero, "<"), target, relational=False)
                    if answer1.is_EmptySet:
                        self.steps.append(["因为\\bigtriangleup > 0", "所以方程有两个不相等的实数根"])
                    elif answer2.is_EmptySet:
                        self.steps.append(["因为\\bigtriangleup < 0", "所以方程没有实数根"])
                    elif answer3.is_EmptySet:
                        self.steps.append(["因为\\bigtriangleup >= 0", "所以方程有实数根"])
                    else:
                        self.steps.append(["因为\\bigtriangleup 的正负性无法判断", "所以无法判断该方程的解"])
                self.label.add("判断含参的一元二次方程解的情况")
        else:
            stepsolver = JieFangChen().solver(args[0])
            self.steps += stepsolver.steps
        return self


# 两根之和
class ErCiLiangGenAdd(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].sympify()
        if not f2.is_zero:
            f = Add(f1, -f2).expand()
            self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
        else:
            f = f1
        symbol = default_symbol(f)
        assert ercifangcheng_judge(f, symbol)
        poly = Poly(f1.as_expr(), symbol)
        a, b, c = poly.all_coeffs()
        add = - b / a
        self.steps.append(["", "两根和为: %s" % (new_latex(add))])
        self.output.append(BaseValue(add))
        self.label.add("两根之和")
        return self


# 两根之积
class ErCiLiangGenMul(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].sympify()
        if not f2.is_zero:
            f = Add(f1, -f2).expand()
            self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
        else:
            f = f1
        symbol = default_symbol(f)
        assert ercifangcheng_judge(f, symbol)
        poly = Poly(f1.as_expr(), symbol)
        a, b, c = poly.all_coeffs()
        mul = c / a
        self.steps.append(["", "两根之积为: %s" % (new_latex(mul))])
        self.output.append(BaseValue(mul))
        self.label.add("两根之积")
        return self


# 韦达定理
class ErCi002(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].sympify()
        var1, var2 = args[1].sympify()
        if not f2.is_zero:
            f = Add(f1, -f2).expand()
            self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
        else:
            f = f1

        if x in f.free_symbols:
            symbol = x
        else:
            symbol = f.free_symbols.pop()
        poly = Poly(f1.as_expr(), symbol)
        a, b, c = poly.all_coeffs()
        if b.is_zero:
            answer = list(solveset(f, symbol, S.Reals))
            self.output.append(BaseSymbolValue({var1: [answer[0]], var2: [answer[1]]}))
        else:
            add = - b / a
            mul = c / a
            self.steps.append(["由韦达定理，得:", self.output_eqs([[var1 + var2, add], [var1 * var2, mul]])])
            self.output.append(BaseEqs([[var1 + var2, add], [var1 * var2, mul]]))
            self.label.add("韦达定理")
        return self


# 已知方程一个根，求参
class ErCi004(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].sympify()
        var1 = args[1].sympify()
        if not f2.is_zero:
            f = Add(f1, -f2).expand()
            self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
        else:
            f = f1

        if x in f.free_symbols:
            symbol = x
        else:
            symbol = f.free_symbols.pop()

        new_f = f.subs({symbol: var1})
        self.steps.append(["因为%s是方程的一个根" % new_latex(var1), self.output_eq([new_f, S.Zero])])
        self.output.append(BaseEq([new_f, S.Zero]))
        self.label.add("已知方程一个根，求参")
        return self


# 根据一元二次方程的定义求参
class ErCi003(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].sympify()
        if not f2.is_zero:
            f = Add(f1, -f2).expand()
            self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
        else:
            f = f1
        symbol = default_symbol(f)

        erci = get_all_child(f, lambda xx: xx.is_Pow and xx.args[0].has(symbol) and (
                not xx.args[1].is_number or xx.args[1] == 2))
        erci_coeff = get_all_child(f, lambda xx: xx.is_Mul and any([xx.has(item) for item in erci]))

        eqs = []
        for expr in erci:
            if expr.args[1] != S.One * 2:
                eqs.append([expr.args[1], S.One * 2])

        for expr in erci_coeff:
            for temp in erci:
                if expr.has(temp):
                    expr = (expr / temp).simplify()
                    if len(expr.free_symbols) > 0:
                        eqs.append([expr, "!=", S.Zero])
                        break

        if len(eqs) > 1:
            self.steps.append(["由一元二次方程的特点得", self.output_eqs(eqs)])
        else:
            self.steps.append(["由一元二次方程的特点得", self.output_eq(eqs[0])])

        self.label.add("根据一元二次方程的定义求参")
        self.output.append(base_gen(eqs))
        return self


# 一元二次方程有不相等的实数根，求参
class ErCi005(BaseFunction):
    op = ">"
    condition = "不相等的实数根"
    label_answer = "一元二次方程有不相等的实数根，求参"

    @staticmethod
    def to_latex(token):
        if token.is_Number and token > 0:
            return new_latex(token)
        else:
            return "(%s)" % new_latex(token)

    def solver(self, *args):
        f1, f2 = args[0].sympify()
        symbol = default_symbol(f1 - f2)

        if not f2.is_zero:
            f = Add(f1, -f2).expand()
            self.steps.append(["整理原方程得", "%s = 0" % new_latex(f)])
        else:
            f = f1

        poly = Poly(f1.as_expr(), symbol)
        a, b, c = poly.all_coeffs()
        latex_a = self.to_latex(a)
        latex_b = self.to_latex(b)
        latex_c = self.to_latex(c)
        parts_a = get_parts(a)
        parts_b = get_parts(b)
        parts_c = get_parts(c)
        ineqs = []
        if len(parts_a) > 0:
            for part in parts_a:
                if part.args[1] == -1 or part.args[1] == 0:
                    ineqs.append([part.args[0], "!=", S.Zero])
                elif (part.args[1].q % 2) == 0:
                    ineqs.append([part.args[0], ">=", S.Zero])
        if len(parts_b) > 0:
            for part in parts_b:
                if part.args[1] == -1 or part.args[1] == 0:
                    ineqs.append([part.args[0], "!=", S.Zero])
                elif (part.args[1].q % 2) == 0:
                    ineqs.append([part.args[0], ">=", S.Zero])
        if len(parts_c) > 0:
            for part in parts_c:
                if part.args[1] == -1 or part.args[1] == 0:
                    ineqs.append([part.args[0], "!=", S.Zero])
                elif (part.args[1].q % 2) == 0:
                    ineqs.append([part.args[0], ">=", S.Zero])
        value = factor(b ** 2 - 4 * a * c)
        if len(args) > 1 and "不-相等" in args[1]:
            self.op = ">"

        ineqs.append([value.simplify(), self.op, S.Zero])
        if len(ineqs) == 1:
            formula = "%s^2-4*%s*%s" % (latex_b, latex_a, latex_c)
            self.steps.append(
                ["因为方程有%s" % self.condition, "\\bigtriangleup = b^2 - 4ac = %s %s 0" % (formula, self.op)])
            value = factor(b ** 2 - 4 * a * c)
            self.steps.append(["整理不等式，得", self.output_eq([value, self.op, S.Zero])])
            if self.op == '=':
                self.output.append(BaseEq([value.simplify(), S.Zero]))
            else:
                self.output.append(BaseIneq([value.simplify(), self.op, S.Zero]))
        else:
            self.steps.append(["依题意，得", self.output_eqs(ineqs)])
            self.output.append(base_gen(ineqs))

        self.label.add(self.label_answer)
        return self


# 一元二次方程有相等的实数根，求参
class ErCi006(ErCi005):
    op = "="
    condition = "相等的实数根"
    label_answer = "一元二次方程有相等的实数根，求参"


# 一元二次方程有实数根，求参
class ErCi007(ErCi005):
    op = ">="
    condition = "实数根"
    label_answer = "一元二次方程有实数根，求参"


# 一元二次方程没有实数根，求参
class ErCi008(ErCi005):
    op = "<"
    condition = "没有实数根"
    label_answer = "一元二次方程没有实数根，求参"


# 将一元二次方程的配方
class ErCiPeiFang(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].sympify()
        f = (f1 - f2).expand().simplify()
        symbol = default_symbol(f)
        poly = Poly(f.as_expr(), symbol)
        a, b, c = poly.all_coeffs()

        if a < 0:
            f = f * (-1)
            poly = Poly(f.as_expr(), symbol)
            a, b, c = poly.all_coeffs()

        constant, f_x = f.as_independent(symbol)
        self.steps.append(["", "%s = %s" % (new_latex(f_x), new_latex(-constant))])

        if a == 1:
            pingfang = (b / 2) ** 2
            left = -constant + pingfang
            self.steps.append(["", "%s + %s = %s + %s" % (new_latex(f_x), new_latex(pingfang), new_latex(-constant), new_latex(pingfang))])
            if b > 0:
                self.steps.append(["", "(%s + %s)**2 = %s" % (new_latex(symbol), new_latex(b / 2), new_latex(left))])
            elif b < 0:
                self.steps.append(["", "(%s - %s)**2 = %s" % (new_latex(symbol), new_latex(-b / 2), new_latex(left))])
        else:
            f_x1 = f_x / a
            self.steps.append(["", "%s*(%s) = %s" % (new_latex(a), new_latex(f_x1), new_latex(-constant))])
            pingfang = (-b / (2 * a)) ** 2
            self.steps.append(["", "%s*(%s + %s - %s) = %s" % (new_latex(a), new_latex(f_x1), new_latex(pingfang),
                                                               new_latex(pingfang), new_latex(-constant))])
            self.steps.append(["", "%s*(%s + %s)- %s * %s = %s" % (new_latex(a), new_latex(f_x1), new_latex(pingfang),
                                                                   new_latex(a), new_latex(pingfang),
                                                                   new_latex(-constant))])
            if b > 0:
                self.steps.append(
                    ["", "%s*(%s + %s)**2 - %s = %s" % (new_latex(a), new_latex(symbol), new_latex(b / (2 * a)),
                                                        new_latex(a * pingfang), new_latex(-constant))])
                self.steps.append(
                    ["", "%s*(%s + %s)**2 = %s" % (new_latex(a), new_latex(symbol), new_latex(b / (2 * a)),
                                                   new_latex(-constant + a * pingfang))])
            elif b < 0:
                self.steps.append(
                    ["", "%s*(%s - %s)**2 - %s = %s" % (new_latex(a), new_latex(symbol), new_latex(-b / (2 * a)),
                                                        new_latex(a * pingfang), new_latex(-constant))])
                self.steps.append(
                    ["", "%s*(%s - %s)**2 = %s" % (new_latex(a), new_latex(symbol), new_latex(-b / (2 * a)),
                                                   new_latex(-constant + a * pingfang))])
        eq_left = a * (symbol + b / (2 * a)) ** 2
        eq_right = (b ** 2 - 4 * a * c) / (4 * a)
        eq = [eq_left, "=", eq_right]
        self.output.append(BaseEq(eq))
        self.label.add("将一元二次方程配方")
        return self


# 求二次函数的二次项系数，一次项系数，常数项系数
class ErCi009(BaseFunction):
    def solver(self, *args):
        f1, f2 = args[0].sympify()
        text = args[1]
        f = (f1 - f2).expand()
        symbol = default_symbol(f)
        poly = Poly(f.as_expr(), symbol)
        a, b, c = poly.all_coeffs()
        self.steps.append(["将方程化为一般形式，得", BaseEq([f, S.Zero]).printing()])
        if "二次项系数" in text:
            self.steps.append(["", "二次项系数是 %s" % (new_latex(a))])
        if "一次项系数" in text:
            self.steps.append(["", "一次项系数是 %s" % (new_latex(b))])
        if "常数项" in text:
            self.steps.append(["", "常数项是 %s" % (new_latex(c))])
        return self


if __name__ == '__main__':
    pass
